package remote.controls
{
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
	
	import remote.IDispose;
	import remote.containers.Container;
	import remote.enums.MouseStatus;
	import remote.events.ChildExistenceChangedEvent;
	import remote.events.MoveEvent;
	import remote.events.ResizeEvent;
	import remote.geom.EdgeMetrics;
	import remote.geom.Size;
	import remote.layouts.AbsoluteLayout;
	import remote.layouts.ILayout;
	import remote.skins.EmptySkin;
	import remote.skins.ISkin;
	import remote.utils.DisplayObjectUtil;
	import remote.utils.NumberUtil;
	import remote.utils.ObjectUtil;
	
	/**
	 * 尺寸改变事件 
	 */	
	[Event(name="resize", type="remote.events.ResizeEvent")]
	
	/**
	 * 位置改变事件 
	 */	
	[Event(name="move", type="remote.events.MoveEvent")]
	
	/**
	 * 添加子项后触发的事件 
	 */	
	[Event(name="childAdd", type="remote.events.ChildExistenceChangedEvent")]
	
	/**
	 * 移除子项前触发的事件 
	 */	
	[Event(name="childRemove", type="remote.events.ChildExistenceChangedEvent")]
	
	/**
	 * 组件基类
	 * @author 银魂飞雪
	 * @createDate 2011-2-25
	 */
	public class Component extends Sprite implements IDispose, IComponent
	{
		private var _listenerDic:Dictionary;
		protected var _width:Number;
		protected var _height:Number;
		protected var _explicitWidth:Number;
		protected var _explicitHeight:Number;
		protected var _skin:ISkin;
		protected var _layout:ILayout;
		protected var _mouseStatus:String;
		protected var _enable:Boolean = true;
		
		protected var _inited:Boolean = false;
		public function Component()
		{
			super();
			this.createSkin();
			this.createLayout();
			this.initProperty();
			this.createChildren();
			this.init();
			
			addHandlers();
		}
		
		/**
		 * @inheritDoc 
		 * 
		 */	
		public function dispose():void
		{
			this.removeAllChildren();
			this.removeAllListener();
			_layout.dispose();
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		public function setSize(width:Number, height:Number):void
		{
			_explicitWidth = width;
			_explicitHeight = height;
			updateSize();
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		public function move(x:Number, y:Number):void
		{
			if(this.x != x || this.y != y)
			{
				var oldPos:Point = new Point(super.x, super.y);
				super.x = x;
				super.y = y;
				this.dispatchEvent(new MoveEvent(MoveEvent.MOVE, oldPos.x, oldPos.y));
			}
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		public function removeAllChildren():void
		{
			while(this.numChildren> 0)
				removeChildAt(0);
		}

		public function getChildren():Array
		{
			return DisplayObjectUtil.getChildren(this);
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		public function removeAllListener():void
		{
			for(var type:String in _listenerDic)
			{
				for(var useCapture:String in _listenerDic[type])
				{
					super.removeEventListener(type, _listenerDic[type][useCapture], useCapture == "true");
				}
			}
			_listenerDic = new Dictionary();
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		override public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
		{
			super.addEventListener(type, listener, useCapture, priority, useWeakReference);
			if(this._listenerDic[type] == null)
			{
				_listenerDic[type] = new Dictionary();
			}
			_listenerDic[type][useCapture.toString()] = listener;
		}
		
		/**
		 * @inheritDoc 
		 * 
		 */	
		override public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
		{
			super.removeEventListener(type, listener, useCapture);
			delete _listenerDic[type][useCapture.toString()];
			if(ObjectUtil.isEmpty(_listenerDic[type]))
				delete _listenerDic[type];
		}
		
		/**
		 * 更新尺寸 
		 * 
		 */		
		public function updateSize():void
		{
			var oldSize:Size = new Size(width, height);
			this.setMeasureOrExplicitSize();
			if(!oldSize.equal(new Size(width, height)))
			{
				updateSkin();
				dispatchEvent(new ResizeEvent(ResizeEvent.RESIZE, oldSize.width, oldSize.height));
				
				var p:Container = parent as Container;
				if(p != null)
					p.updateSize();
			}
		}
		
		/**
		 * 更新皮肤（重绘皮肤） 
		 * 
		 */		
		public function updateSkin():void
		{
			if(_skin != null)
				_skin.draw(this);
		}
		
		/**
		 * 更新布局 
		 * 
		 */		
		public function updateLayout():void
		{
			if(_layout != null)
				_layout.layout();
		}

		/**
		 *  添加事件
		 * 
		 */		
		protected function addHandlers():void
		{
			addEventListener(MouseEvent.ROLL_OVER, mouseEventHandler);
			addEventListener(MouseEvent.ROLL_OUT, mouseEventHandler);
			addEventListener(MouseEvent.MOUSE_DOWN, mouseEventHandler);
			addEventListener(MouseEvent.MOUSE_UP, mouseEventHandler);
			addEventListener(MouseEvent.CLICK, mouseEventHandler, false, int.MAX_VALUE);
		}
		
		/**
		 * 设置尺寸，此方法优先使用显式设置的尺寸 
		 * 
		 */		
		protected function setMeasureOrExplicitSize():void
		{
			var size:Size;
			if(isNaN(this._explicitWidth) || isNaN(this._explicitHeight))
			{
				size = this.getMeasureSize();
				if(!isNaN(this._explicitWidth))
					size.width = _explicitWidth;
				if(!isNaN(this._explicitHeight))
					size.height = _explicitHeight;
			}
			else
			{
				size = new Size(_explicitWidth, _explicitHeight);
			}
			_width = size.width;
			_height = size.height;
		}
		
		/**
		 * 获取测量尺寸 
		 * @return 
		 * 
		 */		
		public function getMeasureSize():Size
		{
			var edge:EdgeMetrics = _layout.edge;
			var childRect:Rectangle = _layout.childrenRect;
			return new Size(edge.left + childRect.x + childRect.width + edge.right, edge.top + childRect.y + childRect.height + edge.bottom);
		}
		
		/**
		 * 初始化属性 
		 * 
		 */		
		protected function initProperty():void
		{
			_listenerDic = new Dictionary();
			_mouseStatus = MouseStatus.OUT;
			_width = 10;
			_height = 10;
		}
		
		/**
		 * 初始化 
		 * 
		 */		
		protected function init():void
		{
			_inited = true;
			updateSkin();
			this.updateLayout();
			//updateChildren();
		}
		
		/**
		 * 创建子对象 
		 * 
		 */		
		protected function createChildren():void
		{
			
		}
		
		/**
		 * 创建布局管理器 
		 * 
		 */		
		protected function createLayout():void
		{
			_layout = new AbsoluteLayout(this);	
		}
		
		/**
		 * 创建皮肤绘制器 
		 * 
		 */		
		protected function createSkin():void
		{
			_skin = new EmptySkin();	
		}
		
		/**
		 * 更新子对象的尺寸，位置 
		 * 
		 */		
		protected function updateChildren():void
		{
			if(_layout != null)
			{
				_layout.layout();
			}
		}
		
		private function mouseEventHandler(e:MouseEvent):void
		{
			switch(e.type)
			{
				case MouseEvent.ROLL_OVER:
					if(!e.buttonDown)
						setMouseStatus(MouseStatus.OVER);
					else
						setMouseStatus(MouseStatus.DOWN);
					break;
				case MouseEvent.MOUSE_DOWN:
					setMouseStatus(MouseStatus.DOWN);
					break;
				case MouseEvent.ROLL_OUT:
					setMouseStatus(MouseStatus.OUT);
					break;
				case MouseEvent.MOUSE_UP:
					setMouseStatus(MouseStatus.OVER);
					break;
				case MouseEvent.CLICK:
					if(!_enable)
					{
						e.stopImmediatePropagation();	
					}
					break;
			}
		}
		
		/**
		 * 设置鼠标状态
		 * 
		 */		
		public function setMouseStatus(value:String):void
		{
			if(_mouseStatus != value)
			{
				_mouseStatus = value;
			}
			
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		override public function addChild(child:DisplayObject):DisplayObject
		{
			var child:DisplayObject = super.addChild(child);
			layout.elements.push(child);
			childAdded(child);
			return child;
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		override public function addChildAt(child:DisplayObject, index:int):DisplayObject
		{
			var child:DisplayObject = super.addChildAt(child, index);
			layout.elements.splice(index, 0, child);
			childAdded(child);
			return child;
		}
		
		private function childAdded(child:DisplayObject):void
		{
			if(this._inited)
			{
				this.updateLayout();
				this.updateSize();
			}
			if(this.hasEventListener(ChildExistenceChangedEvent.CHILD_ADD))
				this.dispatchEvent(new ChildExistenceChangedEvent(ChildExistenceChangedEvent.CHILD_ADD, child));
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		override public function removeChild(child:DisplayObject):DisplayObject
		{
			if(this.hasEventListener(ChildExistenceChangedEvent.CHILD_REMOVE))
				this.dispatchEvent(new ChildExistenceChangedEvent(ChildExistenceChangedEvent.CHILD_REMOVE, child));
			var child:DisplayObject = super.removeChild(child);
			layout.elements.splice(layout.elements.indexOf(child), 0);
			childRemove(child);
			return child;
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		override public function removeChildAt(index:int):DisplayObject
		{
			if(this.hasEventListener(ChildExistenceChangedEvent.CHILD_REMOVE))
				this.dispatchEvent(new ChildExistenceChangedEvent(ChildExistenceChangedEvent.CHILD_REMOVE, super.getChildAt(index)));
			var child:DisplayObject = super.removeChildAt(index);
			layout.elements.splice(index, 1);
			childRemove(child);
			return child;
		}
		
		private function childRemove(child:DisplayObject):void
		{
			if(this._inited)
			{
				this.updateLayout();
				this.updateSize();
			}
			
		}
		
		/**
		* @inheritDoc 
		* 
		*/	
		public function get mouseStatus():String
		{
			return _mouseStatus;
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		public function get skinStatus():String
		{
			return "normal";
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		public function set skin(value:ISkin):void
		{
			if(_skin != value)
			{
				_skin = value;
				if(_inited)
					updateSkin();
			}
		}
		
		public function get skin():ISkin
		{
			return _skin;
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		override public function get width():Number
		{
			return _width;
		}

		override public function set width(value:Number):void
		{
			if(!NumberUtil.equal(this._explicitWidth, value))
			{
				this.setSize(value, this._explicitHeight);
			}
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		override public function get height():Number
		{
			return _height;
		}

		override public function set height(value:Number):void
		{
			if(!NumberUtil.equal(this._explicitHeight, value))
			{
				setSize(_explicitWidth, value);
			}
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		public function get layout():ILayout
		{
			return _layout;
		}

		public function set layout(value:ILayout):void
		{
			if(_layout != value)
			{
				_layout.dispose();
				_layout = value;
				_layout.target = this;
				if(_inited)
				{
					this.updateSize();
					_layout.layout();
				}
				
			
			}
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		public function set enable(value:Boolean):void
		{
			if(_enable != value)
			{
				_enable = value;
				updateSkin();
				for(var i:int = 0; i < this.numChildren; i++)
				{
					var child:DisplayObject = this.getChildAt(i);
					if(child.hasOwnProperty("enable"))
						child["enable"] = _enable;
				}
			}
		}
		
		public function get enable():Boolean
		{
			return _enable;
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		override public function set x(value:Number):void
		{
			if(this.x != value)
			{
				move(value, y);
			}
		}
		/**
		 * @inheritDoc 
		 * 
		 */	
		override public function set y(value:Number):void
		{
			if(this.y != value)
			{
				move(x, value);
			}
		}
	}
}